package schema

import (
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/pkg/errors"
)

// ConvertTableToDst 将Schema Table转换为GORM模型类型
func ConvertTableToDst(table Table) (interface{}, error) {
	fields := make([]reflect.StructField, 0, len(table.Fields))

	// 处理字段
	for _, field := range table.Fields {
		var goType reflect.Type
		var gormTag string
		var tags []string
		var err error

		switch field.Role {
		case RolePrimary:
			goType, gormTag, tags, err = processPrimaryField(field)
		case RoleForeign:
			goType, gormTag, tags, err = processForeignField(field)
		case RoleNormal:
			goType, gormTag, tags, err = processNormalField(field)
		case RoleFormula:
			goType, gormTag, tags, err = processFormulaField(field)
		case RoleExpr:
			goType, gormTag, tags, err = processExprField(field)
		default:
			return nil, errors.Wrap(fmt.Errorf("不支持的字段角色: %s", field.Role), "DATA016")
		}

		if err != nil {
			return nil, err
		}

		// 基础标签处理
		baseTags := []string{fmt.Sprintf("column:%s", field.Name)}
		if gormTag != "" {
			baseTags = append(baseTags, gormTag)
		}
		baseTags = append(baseTags, tags...)

		// 添加字段
		fields = append(fields, reflect.StructField{
			Name: field.Name,
			Type: goType,
			Tag:  reflect.StructTag(fmt.Sprintf("gorm:\"%s\" json:\"%s\"", strings.Join(baseTags, ";"), field.Name)),
		})
	}

	// 创建模型
	modelType := reflect.StructOf(fields)
	return reflect.New(modelType).Interface(), nil
}

// processPrimaryField 处理主键字段
func processPrimaryField(field Field) (reflect.Type, string, []string, error) {

	// 类型映射
	var goType reflect.Type
	var gormTag string
	switch field.Type {
	case TypeInt:
		goType = reflect.TypeOf(int(0))
	case TypeVarchar:
		goType = reflect.TypeOf("")
	default:
		return nil, "", nil, errors.Errorf("主键字段'%s'类型不支持", field.Name)
	}

	// 主键标签
	tags := []string{"primaryKey"}
	if field.AutoIncrement {
		tags = append(tags, "autoIncrement")
	}
	if field.Index {
		tags = append(tags, "index")
	}

	return goType, gormTag, tags, nil
}

// processForeignField 处理外键字段
func processForeignField(field Field) (reflect.Type, string, []string, error) {
	// 外键类型验证和处理
	var goType reflect.Type
	switch field.Type {
	case TypeInt:
		goType = reflect.TypeOf(int(0))
	case TypeVarchar:
		goType = reflect.TypeOf("")
	default:
		return nil, "", nil, errors.Errorf("外键字段'%s'类型不支持", field.Name)
	}

	// 解析外键引用
	if field.References == "" {
		return nil, "", nil, errors.Errorf("外键字段'%s'未指定References", field.Name)
	}
	parts := strings.Split(field.References, ".")
	if len(parts) != 2 {
		return nil, "", nil, errors.Errorf("外键引用格式错误，应为'Table.Field': %s", field.References)
	}
	refTable := parts[0]
	refField := parts[1]

	// 构建外键标签
	tags := []string{fmt.Sprintf("foreignKey:%s", field.Name)}
	if field.Index {
		tags = append(tags, "index")
	}

	// 添加引用和级联规则 - 修复外键表名缺失问题
	gormTag := fmt.Sprintf("references:%s(%s)", refTable, refField)
	if field.OnDelete != "" {
		gormTag += fmt.Sprintf(";onDelete:%s", field.OnDelete)
	}
	if field.OnUpdate != "" {
		gormTag += fmt.Sprintf(";onUpdate:%s", field.OnUpdate)
	}

	return goType, gormTag, tags, nil
}

// processNormalField 处理普通字段
func processNormalField(field Field) (reflect.Type, string, []string, error) {
	goType, gormTag, err := getBasicTypeInfo(field)
	if err != nil {
		return nil, "", nil, err
	}

	tags := []string{}
	if field.Index {
		tags = append(tags, "index")
	}

	// 处理默认值
	if field.Default != nil {
		defaultStr := fmt.Sprintf("default:%v", field.Default)
		tags = append(tags, defaultStr)
	}

	return goType, gormTag, tags, nil
}

// processFormulaField 处理公式字段
func processFormulaField(field Field) (reflect.Type, string, []string, error) {
	goType, gormTag, err := getBasicTypeInfo(field)
	if err != nil {
		return nil, "", nil, err
	}

	tags := []string{}
	// 公式字段不支持索引
	// 添加公式字段标记
	if field.ExprField != "" {
		tags = append(tags, fmt.Sprintf("exprField:%s", field.ExprField))
	}
	if field.DefaultExpr != "" {
		tags = append(tags, fmt.Sprintf("defaultExpr:%s", field.DefaultExpr))
	}

	return goType, gormTag, tags, nil
}

// processExprField 处理EXPR字段
func processExprField(field Field) (reflect.Type, string, []string, error) {
	// EXPR字段必须是TEXT类型
	if field.Type != TypeText {
		return nil, "", nil, errors.Errorf("EXPR字段'%s'必须是TEXT类型", field.Name)
	}

	// EXPR字段不能设置表达式相关字段
	if field.ExprField != "" || field.DefaultExpr != "" {
		return nil, "", nil, errors.Errorf("EXPR字段'%s'不能设置ExprField或DefaultExpr", field.Name)
	}

	// EXPR字段使用TEXT类型
	goType := reflect.TypeOf("")
	gormTag := "type:text"

	// EXPR字段不支持索引
	tags := []string{}

	return goType, gormTag, tags, nil
}

// getBasicTypeInfo 获取基础类型信息
func getBasicTypeInfo(field Field) (reflect.Type, string, error) {
	var goType reflect.Type
	var gormTag string

	switch field.Type {
	case TypeInt:
		goType = reflect.TypeOf(int(0))
	case TypeFloat:
		goType = reflect.TypeOf(float64(0))
		// 根据Precision和Scale设置decimal精度
		if field.Precision > 0 && field.Scale > 0 {
			gormTag = fmt.Sprintf("type:decimal(%d,%d)", field.Precision, field.Scale)
		} else if field.Precision > 0 {
			gormTag = fmt.Sprintf("type:decimal(%d, 6)", field.Precision)
		} else if field.Scale > 0 {
			gormTag = fmt.Sprintf("type:decimal(30, %d)", field.Scale)
		} else {
			gormTag = "type:decimal(30,6)" // 默认精度：30位数字，6位小数
		}
	case TypeVarchar:
		goType = reflect.TypeOf("")
	case TypeText:
		goType = reflect.TypeOf("")
		gormTag = "type:text"
	case TypeDate:
		goType = reflect.TypeOf(time.Time{})
		gormTag = "type:date"
	case TypeDatetime:
		goType = reflect.TypeOf(time.Time{})
		gormTag = "type:datetime"
	case TypeArray, TypeMap:
		goType = reflect.TypeOf("")
		gormTag = "type:json"
	default:
		return nil, "", errors.Wrap(fmt.Errorf("不支持的字段类型: %s", field.Type), "DATA015")
	}

	return goType, gormTag, nil
}
